package com.tedu.manager;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import javax.swing.ImageIcon;

import com.tedu.element.ElementObj;
import com.tedu.element.map.MapAware;
import com.tedu.element.map.TileType;
import com.tedu.element.player.P1InputStrategy;
import com.tedu.element.player.P2InputStrategy;
import com.tedu.element.player.Player;

/**
 * @说明 通用资源加载器。负责加载图片、游戏对象类、玩家等
 * <p> 此类中的所有方法都应是静态的，作为工具类使用
 */
public class GameLoad {
    //	资源管理器
    private static final ElementManager em = ElementManager.getManager();

    //	用于存储单个图片资源
    public static final Map<String, ImageIcon> imgMap = new HashMap<>();

    /**
     * 用于存储成组的图片资源, 例如动画帧、多状态对象等
     * <p>外层 Key: 资源组名
     * <p>内层 Key: 状态名
     */
    public static final Map<String, Map<String, ImageIcon>> groupImgMap = new HashMap<>();

    //	用户读取文件的类
    private static final Properties pro = new Properties();

    // 用于存储通过反射加载的类定义
    private static final Map<String, Class<?>> objMap = new HashMap<>();

    private static final Map<Integer, TileType> CODE_MAP = new HashMap<>();

    // 私有化构造函数，防止外部实例化
    private GameLoad() {
    }

    /**
     * 游戏启动时加载所有核心资源。
     * 这个方法应该在游戏循环开始前被调用一次
     */
    public static void loadCoreResources() {
        // 1. 加载并初始化 TileType 数据
        loadTileTypeData();
        // 2. 加载图片资源
        loadImg();
        // 3. 加载对象类定义
        loadObj();
    }

    /**
     * 从配置文件加载并初始化 TileType 枚举的属性
     */
    private static void loadTileTypeData() {
        String path = "com/tedu/text/tiles.pro";
        ClassLoader classLoader = GameLoad.class.getClassLoader();

        try (InputStream texts = classLoader.getResourceAsStream(path)) {
            if (texts == null) {
                System.err.println("警告: Tile配置文件未找到: " + path + ", 将使用默认Tile属性。");
                return;
            }
            pro.load(texts);

            for (TileType type : TileType.values()) {
                type.init(pro);
                CODE_MAP.put(type.getCode(), type);
            }

        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 通过 code 获取 TileType
     */
    public static TileType fromCode(int code) {
        TileType type = CODE_MAP.get(code);
        if (type == null) {
            // 如果找不到，返回 EMPTY 作为默认值
            System.err.println("警告: 无效的格子类型代码: " + code + "，已替换为空地。");
            return TileType.EMPTY;
        }
        return type;
    }

    /**
     * @说明 加载图片，识别单个图片和成组图片目录
     * <ul>
     * <li><p> 如果配置文件中的 key 不以 ".states" 结尾, 则视为单个图片资源, 加载到 imgMap中
     * <li><p> 如果 key 以 ".states" 结尾, 则视为成组的图片资源
     * </ul>
     */
    private static void loadImg() {
        String path = "com/tedu/text/image.pro";//文件的命名可以更加有规律
        ClassLoader classLoader = GameLoad.class.getClassLoader();
        InputStream texts = classLoader.getResourceAsStream(path);

        pro.clear();
        try {
            if (texts == null) {
                System.err.println("错误: 无法找到资源配置文件: " + path);
                return;
            }
            pro.load(texts);

            Set<Object> keys = pro.keySet();
            for (Object keyObj : keys) {
                String key = keyObj.toString();
                String value = pro.getProperty(key);

                if (key.endsWith(".states")) {
                    // 处理成组的资源
                    loadGroupImages(key, pro, classLoader);
                } else if (!key.contains(".")){
                    // 处理单个图片资源
                    URL imgUrl = classLoader.getResource(value);
                    if (imgUrl != null) {
                        imgMap.put(key, new ImageIcon(imgUrl));
                    } else {
                        System.err.println("警告: 在类路径中找不到图片资源: " + value);
                    }
                }
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * @说明 加载一个目录下的所有图片作为一组资源
     * <ul>
     * <li><p> 将 key的前缀作为资源组名
     * <li><p> 将 value作为目录路径, 遍历该目录下的所有图片文件。
     * <li><p> 将每个图片的文件名(不含扩展名)作为状态名, 与图片本身一起存入 groupImgMap
     * </ul>
     */
    private static void loadGroupImages(String stateKey, Properties props, ClassLoader classLoader) {
        // 提取资源组名称
        String groupName = stateKey.substring(0, stateKey.lastIndexOf('.'));

        // 获取资源组的路径、状态列表和扩展名
        String basePath = props.getProperty(groupName + ".path");
        String states = props.getProperty(stateKey);
        String extension = props.getProperty(groupName + ".extension", ".png"); // 默认为.png

        if (basePath == null || states == null) {
            System.err.println("警告: 资源组 '" + groupName + "' 配置不完整，已跳过。");
            return;
        }

        Map<String, ImageIcon> group = new HashMap<>();
        groupImgMap.put(groupName, group);

        // 遍历所有状态，构建完整路径并加载
        for (String state : states.split(",")) {
            state = state.trim();
            String fullPath = basePath + state + extension;
            URL imgUrl = classLoader.getResource(fullPath);
            if (imgUrl != null) {
                group.put(state, new ImageIcon(imgUrl));
            } else {
                System.err.println("警告: 在类路径中找不到资源组图片: " + fullPath);
            }
        }
    }

    /**
     * 根据配置字符串创建一个玩家实例。
     *
     * @param config   格式为 "gridX,gridY,imageName"
     * @param playerID 玩家ID (1 或 2)
     * @return 创建好的 Player 对象，如果失败则返回 null
     */
    public static ElementObj createPlayer(String config, int playerID) {
        if (objMap.isEmpty()) {
            loadObj(); // 确保类定义已加载
        }
        ElementObj obj = getObj("player");
        if (obj != null) {
            Player player = (Player) obj;
            // 设置玩家ID
            player.setPlayerID(playerID);
            // 根据 ID设置不同的输入策略
            if (playerID == 1) {
                player.setInputStrategy(new P1InputStrategy());
            } else if (playerID == 2) {
                player.setInputStrategy(new P2InputStrategy());
            }

            player.createElement(config);
            ((MapAware) player).setGameMap(em.getGameMap());

            return player;
        }
        return null;
    }

    /**
     * 根据字符串key从配置中获取并实例化一个 ElementObj对象。
     *
     * @param key 在 obj.pro中定义的 key
     * @return 实例化后的 ElementObj，如果失败则返回 null
     */
    public static ElementObj getObj(String key) {
        try {
            Class<?> clazz = objMap.get(key);
            if (clazz != null && ElementObj.class.isAssignableFrom(clazz)) {
                return (ElementObj) clazz.newInstance();
            }
        } catch (Exception e) {
            System.err.println("通过反射实例化对象时出错: " + key);
            throw new RuntimeException(e);
        }
        return null;
    }

    /**
     * 加载 obj.pro文件中定义的所有游戏对象类
     */
    private static void loadObj() {
        String path = "com/tedu/text/obj.pro";
        ClassLoader classLoader = GameLoad.class.getClassLoader();

        try (InputStream texts = classLoader.getResourceAsStream(path)) {
            if (texts == null) {
                System.err.println("错误: 无法找到对象配置文件: " + path);
                return;
            }
            pro.clear();
            pro.load(texts);

            for (Object keyObj : pro.keySet()) {
                String key = keyObj.toString();
                String className = pro.getProperty(key);
                try {
                    Class<?> clazz = Class.forName(className);
                    objMap.put(key, clazz);
                } catch (ClassNotFoundException e) {
                    System.err.println("错误: 找不到类定义: " + className);
                }
            }
        } catch (IOException e) {
            System.err.println("加载对象配置文件时出错: " + path);
            throw new RuntimeException(e);
        }
    }
}
